package dice.sinanya.dice.manager;

import com.forte.qqrobot.beans.messages.types.PowerType;
import dice.sinanya.db.roles.InsertRoles;
import dice.sinanya.dice.manager.imal.AtQq;
import dice.sinanya.dice.manager.imal.Role;
import dice.sinanya.entity.EntityRoleTag;
import dice.sinanya.entity.EntityStrManyRolls;
import dice.sinanya.entity.EntityTeamInfo;
import dice.sinanya.entity.EntityTypeMessages;
import dice.sinanya.entity.imal.GetDb;
import dice.sinanya.exceptions.*;
import dice.sinanya.tools.makedata.MakeSanCheck;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.nlpcn.commons.lang.util.StringUtil;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;
import java.util.regex.Pattern;

import static dice.sinanya.dice.roll.RiAndInit.sortHashMapByKey;
import static dice.sinanya.system.MessagesSystem.NONE;
import static dice.sinanya.system.MessagesSystem.loginInfo;
import static dice.sinanya.system.MessagesTag.*;
import static dice.sinanya.system.RoleInfoCache.ROLE_INFO_CACHE;
import static dice.sinanya.tools.checkdata.CheckCantInPrivate.checkCantInPrivate;
import static dice.sinanya.tools.checkdata.CheckIsNumbers.isNumeric;
import static dice.sinanya.tools.getinfo.GetMessagesProperties.entitySystemProperties;
import static dice.sinanya.tools.getinfo.GetNickName.getNickName;
import static dice.sinanya.tools.getinfo.RoleChoose.checkRoleChooseExistByQQ;
import static dice.sinanya.tools.getinfo.RoleChoose.getRoleChooseByQQ;
import static dice.sinanya.tools.getinfo.RoleInfo.getRoleInfoFromChooseByQQ;
import static dice.sinanya.tools.getinfo.RoleInfo.setRoleInfoFromChooseByQQ;
import static dice.sinanya.tools.getinfo.RoleLock.checkRoleLock;
import static dice.sinanya.tools.getinfo.RoleLock.getRoleLockName;
import static dice.sinanya.tools.getinfo.Team.*;
import static dice.sinanya.tools.makedata.GetRollResultAndStr.getResFunctionAndResultInt;
import static dice.sinanya.tools.makedata.MakeMessages.deleteTag;
import static dice.sinanya.tools.makedata.Sender.sender;
import static dice.sinanya.tools.makedata.StringFormatById.stringFormatById;
import static java.lang.Integer.min;
import static java.lang.Math.max;

/**
 * @author SitaNya
 * 日期: 2019-06-15
 * 电子邮箱: sitanya@qq.com
 * 维护群(QQ): 162279609
 * 有任何问题欢迎咨询
 * 类说明: 管理小队
 */
public class Team implements GetDb, Role, AtQq {
    private static final Logger log = LogManager.getLogger(Team.class.getName());


    private final Pattern plus = Pattern.compile("[+*/\\-]");

    private final EntityTypeMessages entityTypeMessages;

    public Team(EntityTypeMessages entityTypeMessages) {
        this.entityTypeMessages = entityTypeMessages;
    }

    /**
     * 将@到的成员加入小队
     */
    public void set() throws CantInPrivateException {
        checkCantInPrivate(entityTypeMessages);
        String tag = TAG_TEAM_SET;
        String msg = deleteTag(entityTypeMessages.getMsgGet().getMsg(), tag.substring(0, tag.length() - 2));
        if (msg.equals(NONE)) {
            sender(entityTypeMessages, entitySystemProperties.getTeamFormatError(entityTypeMessages.getFromGroupString()));
            return;
        }
        ArrayList<String> qqList = getAtQqList(entityTypeMessages, msg);
        ArrayList<String> result = new ArrayList<>();
        result.add("已将玩家:");
        for (String qq : qqList) {
            result.add(stringFormatById("[CQ:at,qq=%s]", qq));
        }
        result.add(stringFormatById(entitySystemProperties.getTeamInsert(entityTypeMessages.getFromGroupString())));
        EntityTeamInfo entityTeamInfo = new EntityTeamInfo(entityTypeMessages.getFromGroupString(), qqList);
        addIntoTeam(entityTeamInfo);
        sender(entityTypeMessages, StringUtil.joiner(result, "\n"));
    }

    /**
     * 将@到的成员移出小队，也会清空该队员的技能成功记录
     */
    public void remove() throws CantInPrivateException {
        checkCantInPrivate(entityTypeMessages);
        String tag = TAG_TEAM_RM;
        String msg = deleteTag(entityTypeMessages.getMsgGet().getMsg(), tag.substring(0, tag.length() - 2));
        ArrayList<String> qqList = getAtQqList(entityTypeMessages, msg);
        EntityTeamInfo entityTeamInfo = new EntityTeamInfo(entityTypeMessages.getFromGroupString(), qqList);
        removeFromTeam(entityTeamInfo);
        for (String qq : qqList) {
            rmTeamEn(qq, entityTypeMessages.getFromGroupString());
            sender(entityTypeMessages, stringFormatById(entitySystemProperties.getTeamRemove(entityTypeMessages.getFromGroupString()), "[CQ:at,qq=" + qq + "]"));
        }
    }

    /**
     * 将本群小队清空，也会清空队员的技能成功记录
     */
    public void clr() throws CantInPrivateException {
        checkCantInPrivate(entityTypeMessages);
        clearTeam(entityTypeMessages.getFromGroupString());
        clrTeamEn(entityTypeMessages.getFromGroupString());
        sender(entityTypeMessages, entitySystemProperties.getTeamClear(entityTypeMessages.getFromGroupString()));
    }

    /**
     * 自动@本群小队中所有成员
     */
    public void call() throws CantInPrivateException {
        checkCantInPrivate(entityTypeMessages);
        StringBuilder stringBuilder = new StringBuilder();
        stringBuilder.append(entitySystemProperties.getTeamCall(entityTypeMessages.getFromGroupString()));
        for (String qq : queryTeam(entityTypeMessages.getFromGroupString())
        ) {
            stringBuilder.append("\n[CQ:at,qq=")
                    .append(qq)
                    .append("]");
        }
        sender(entityTypeMessages, stringBuilder.toString());
    }

    /**
     * 调整@到的小队成员的血量，默认为减少，可以使用1D3或1D3+20之类的表达式，每个小队成员都会单独计算表达式
     * 使用+为前缀则恢复血量
     */
    public void hp() throws ManyRollsTimesTooMoreException, RollCantInZeroException, CantInPrivateException {
        String msg = checkHeader(TAG_TEAM_HP);
        String groupId = entityTypeMessages.getFromGroupString();
        ArrayList<String> qqList = getAtQqList(entityTypeMessages, msg);
        String regex = "\\[cq:at,qq=([0-9]+).*]";
        msg = msg.replaceAll(regex, "").replace("all", "").trim();
        boolean add = false;
        if (msg.matches("^\\+.*")) {
            msg = msg.replaceAll("\\+", "");
            add = true;
        }
        String[] everyFunction = msg.split(plus.toString());
        for (String qq : qqList) {

            EntityStrManyRolls entityStrManyRolls = getResFunctionAndResultInt(entityTypeMessages, msg, everyFunction);

            String role;
            int hp;
            HashMap<String, Integer> prop = (HashMap<String, Integer>) getRoleInfoFromChooseByQQ(qq, groupId);
            if (prop != null) {

                role = getRoleChooseByQQ(qq, groupId);
                hp = prop.get("hp");
                int con = prop.get("con");
                int siz = prop.get("siz");
                int hpc = prop.getOrDefault("hpc", 0);
                if (add) {
                    int maxHp = (con + siz) / 10 + hpc;
                    int newHp = min(hp + (int) entityStrManyRolls.getResult(), maxHp);
                    prop.put("hp", newHp);
                    setRoleInfoFromChooseByQQ(qq, groupId, prop);
                    sender(entityTypeMessages, "已为" + role + "恢复" + entityStrManyRolls.getStrFunction() + "=" + entityStrManyRolls.getResult() + "点血量，剩余" + newHp + "点");
                } else {
                    int newHp = max(0, hp - (int) entityStrManyRolls.getResult());
                    prop.put("hp", newHp);
                    setRoleInfoFromChooseByQQ(qq, groupId, prop);
                    ROLE_INFO_CACHE.put(new EntityRoleTag(Long.parseLong(qq), role), prop);
                    if (newHp == 0) {
                        sender(entityTypeMessages, role + "损失" + entityStrManyRolls.getStrFunction() + "=" + entityStrManyRolls.getResult() + "点血量，已死亡");
                    } else if ((int) entityStrManyRolls.getResult() >= hp / 2) {
                        sender(entityTypeMessages, "已为" + role + "降低" + entityStrManyRolls.getStrFunction() + "=" + entityStrManyRolls.getResult() + "点血量，剩余" + newHp + "点,已进入重伤状态");
                    } else {
                        sender(entityTypeMessages, "已为" + role + "降低" + entityStrManyRolls.getStrFunction() + "=" + entityStrManyRolls.getResult() + "点血量，剩余" + newHp + "点");
                    }
                }
            } else {
                sender(entityTypeMessages, stringFormatById(entitySystemProperties.getTeamNotChooseRole(entityTypeMessages.getFromGroupString()), "[CQ:at,qq=" + qq + "]"));
            }
        }
    }

    /**
     * 调整@到的小队成员的理智值，默认为减少，可以使用1D3/1d6或1D3+20之类的表达式，每个小队成员都会单独计算表达式
     * 使用+为前缀则恢复理智值
     */
    public void san() throws CantInPrivateException, NotSetKpGroupException {
        String msg = checkHeader(TAG_TEAM_SAN);
        ArrayList<String> qqList = getAtQqList(entityTypeMessages, msg);
        String regex = "\\[cq:at,qq=([0-9]+).*]";
        msg = msg.replaceAll(regex, "").replace("all", "").trim();
        boolean add = false;
        String groupId = entityTypeMessages.getFromGroupString();
        if (msg.matches("^\\+.*")) {
            msg = msg.replaceAll("\\+", "");
            add = true;
        }
        for (String qq : qqList) {

            MakeSanCheck makeSanCheck = new MakeSanCheck(entityTypeMessages, qq);

            if (add) {
                try {
                    makeSanCheck.addSanCheck(msg);
                } catch (PlayerSetException e) {
                    log.error(e.getMessage(), e);
                }
            } else {
                try {
                    if (msg.contains("/")) {
                        String result = makeSanCheck.checkSanCheck(msg, qq);
                        sender(entityTypeMessages, result);
                    } else {
                        int changeValue;
                        if (isNumeric(msg)) {
                            changeValue = Integer.parseInt(msg);
                        } else {
                            String[] everFunctions = msg.split(plus.toString());
                            changeValue = (int) getResFunctionAndResultInt(entityTypeMessages, msg, everFunctions).getResult();
                        }
                        HashMap<String, Integer> prop = (HashMap<String, Integer>) getRoleInfoFromChooseByQQ(qq, groupId);
                        if (prop != null) {
                            StringBuilder strResult = new StringBuilder();
                            int newSan = max(0, prop.get("san") - changeValue);
                            newSan = min(newSan, 99 - prop.get("cthulhuMythos"));
                            String role = getRoleChooseByQQ(qq, groupId);
                            strResult.append("已为").append(role).append("减少").append(changeValue).append("点理智值，剩余").append(newSan).append("点");
                            if (newSan == 0) {
                                strResult.append("\n已永久疯狂");
                            } else if (changeValue >= 5) {
                                strResult.append("\n已进入临时性疯狂");
                            } else if (changeValue >= prop.get("san") / 5) {
                                strResult.append("\n已因单次损失值进入不定性疯狂");
                            }
                            prop.put("san", newSan);
                            setRoleInfoFromChooseByQQ(qq, groupId, prop);
                            ROLE_INFO_CACHE.put(new EntityRoleTag(Long.parseLong(qq), role), prop);
                            sender(entityTypeMessages, strResult.toString());
                        } else {
                            sender(entityTypeMessages, stringFormatById(entitySystemProperties.getTeamNotChooseRole(entityTypeMessages.getFromGroupString()), "[CQ:at,qq=" + qq + "]"));
                        }
                    }

                } catch (SanCheckSetException | PlayerSetException | ManyRollsTimesTooMoreException | RollCantInZeroException e) {
                    log.error(e.getMessage(), e);
                }
            }
        }
    }

    /**
     * 显示当前小队的情况，会根据小队成员的当前激活人物自动计算得出
     */
    public void show() throws PlayerSetException, CantInPrivateException {
        checkCantInPrivate(entityTypeMessages);
        StringBuilder stringBuilder = new StringBuilder();
        String groupId = entityTypeMessages.getFromGroupString();
        ArrayList<String> result = new ArrayList<>();
        HashMap<String, Integer> propListForQq = new HashMap<>();
        result.add(entitySystemProperties.getTeamShow(entityTypeMessages.getFromGroupString()));
        ArrayList<String> qqList = (ArrayList<String>) queryTeam(entityTypeMessages.getFromGroupString());
        if (qqList == null) {
            try {
                throw new TeamIsEmptyException(entityTypeMessages);
            } catch (TeamIsEmptyException e) {
                log.error(e.getMessage(), e);
                return;
            }
        }
        for (String qq : qqList) {
            HashMap<String, Integer> prop = (HashMap<String, Integer>) getRoleInfoFromChooseByQQ(qq, groupId);
            if (prop != null) {
                String role = getRoleChooseByQQ(qq, groupId);
                try {
                    int str = prop.get("str");
                    int pow = prop.get("pow");
                    int con = prop.get("con");
                    int siz = prop.get("siz");
                    int san = prop.get("san");
                    int hp = prop.get("hp");
                    int dex = prop.getOrDefault("dex", 0);
                    int hpc = prop.getOrDefault("hpc", 0);
                    int cthulhuMythos = prop.get("cthulhuMythos");

                    if (hp > (con + siz) / 10 + hpc) {
                        hp = (con + siz) / 10 + hpc;
                        prop.put("hp", hp);
                        setRoleInfoFromChooseByQQ(qq, groupId, prop);
                    }
                    if (san > (99 - cthulhuMythos)) {
                        san = 99 - cthulhuMythos;
                        prop.put("san", san);
                        setRoleInfoFromChooseByQQ(qq, groupId, prop);
                    }
                    propListForQq.put(stringFormatById("%s 血量:%s/%s san:%s/%s(初始值%s) DB:%s 敏捷:%s", role, hp, (con + siz) / 10 + hpc, san, 99 - cthulhuMythos, pow, dbGetter(siz + str), dex), dex);
                } catch (NullPointerException e) {
                    throw new PlayerSetException(entityTypeMessages);
                }
            } else {
                propListForQq.put(stringFormatById(entitySystemProperties.getTeamNotChooseRole(entityTypeMessages.getFromGroupString()), qq), 0);
            }
        }
        for (Map.Entry<String, Integer> map : sortHashMapByKey(propListForQq).entrySet()) {
            result.add(map.getKey());
        }
        sender(entityTypeMessages, StringUtil.joiner(result, "\n"));
    }

    /**
     * 显示当前小队所有成员当前激活角色的技能情况，私聊发送给命令触发人
     */
    public void desc() throws CantInPrivateException {
        checkCantInPrivate(entityTypeMessages);
        StringBuilder stringBuilder = new StringBuilder();

        ArrayList<String> qqList = (ArrayList<String>) queryTeam(entityTypeMessages.getFromGroupString());
        if (qqList == null) {
            try {
                throw new TeamIsEmptyException(entityTypeMessages);
            } catch (TeamIsEmptyException e) {
                log.error(e.getMessage(), e);
                return;
            }
        } else {
            stringBuilder.append(entitySystemProperties.getTeamProp(entityTypeMessages.getFromGroupString()));
        }
        for (String qq : qqList) {
            stringBuilder.append(new Roles(entityTypeMessages).showProp(qq, entityTypeMessages.getFromGroupString()));
        }
        entityTypeMessages.getMsgSender().SENDER.sendPrivateMsg(entityTypeMessages.getFromQqString(), stringBuilder.toString());
    }

    /**
     * 显示当前小队所有成员当前激活角色的技能成功情况
     */
    public void en() throws CantInPrivateException {
        checkCantInPrivate(entityTypeMessages);
        StringBuilder stringBuilder = new StringBuilder();

        ArrayList<String> qqList = (ArrayList<String>) queryTeam(entityTypeMessages.getFromGroupString());
        if (qqList == null) {
            try {
                throw new TeamIsEmptyException(entityTypeMessages);
            } catch (TeamIsEmptyException e) {
                log.error(e.getMessage(), e);
                return;
            }
        } else {
            stringBuilder.append(entitySystemProperties.getTeamEn(entityTypeMessages.getFromGroupString()));
        }
        for (String qq : qqList) {
            stringBuilder.append(getTeamEn(entityTypeMessages, qq)).append("\n");
        }
        sender(entityTypeMessages, stringBuilder.substring(0, stringBuilder.length() - 1));
    }

    private String checkHeader(String tag) throws CantInPrivateException {
        checkCantInPrivate(entityTypeMessages);
        String msg = deleteTag(entityTypeMessages.getMsgGet().getMsg(), tag.substring(0, tag.length() - 2));

//        String regex = "\\[cq:at,qq=([0-9]+).*]");";
//        msg = msg.replaceAll(regex, "").trim();
        return msg;
    }

    public void teamLock() {
        ArrayList<String> qqList = (ArrayList<String>) queryTeam(entityTypeMessages.getFromGroupString());
        for (String qq : qqList) {
            lock(Long.parseLong(qq));
        }
    }

    public void teamRename() {
        if (checkPower(loginInfo.getLoginId()).equals(PowerType.MEMBER)) {
            sender(entityTypeMessages, entitySystemProperties.getTeamRename(entityTypeMessages.getFromGroupString()));
            return;
        }
        ArrayList<String> qqList = (ArrayList<String>) queryTeam(entityTypeMessages.getFromGroupString());
        for (String qq : qqList) {
            HashMap<String, Integer> prop = (HashMap<String, Integer>) getRoleInfoFromChooseByQQ(String.valueOf(qq), entityTypeMessages.getFromGroupString());
            int con;
            int siz;
            int san = 0;
            int hp = 0;
            int dex = 0;
            int hpc;
            int cthulhuMythos;
            int hpMax = 0;
            int sanMax = 0;
            if (prop != null) {
                con = prop.getOrDefault("con", 0);
                siz = prop.getOrDefault("siz", 0);
                hpc = prop.getOrDefault("hpc", 0);
                cthulhuMythos = prop.getOrDefault("cthulhuMythos", 0);
                hp = prop.getOrDefault("hp", 0);
                san = prop.getOrDefault("san", 0);
                dex = prop.getOrDefault("dex", 0);
                hpMax = (con + siz) / 10 + hpc;
                sanMax = 99 - cthulhuMythos;
            }
            String newNick = stringFormatById("%s hp:%s/%s san:%s/%s dex:%s", getNickName(Long.parseLong(qq), entityTypeMessages), hp, hpMax, san, sanMax, dex);
            if (newNick.length() > 50) {
                newNick = stringFormatById("%s hp:%s/%s san:%s/%s", getNickName(Long.parseLong(qq), entityTypeMessages), hp, hpMax, san, sanMax);
            }

            if (newNick.length() > 50) {
                newNick = stringFormatById("%s hp:%s/%s san:%s", getNickName(Long.parseLong(qq), entityTypeMessages), hp, hpMax, san);
            }

            if (newNick.length() > 50) {
                newNick = stringFormatById("%s hp:%s san:%s", getNickName(Long.parseLong(qq), entityTypeMessages), hp, san);
            }

            if (newNick.length() > 50) {
                newNick = stringFormatById("%s hp:%s", getNickName(Long.parseLong(qq), entityTypeMessages), hp);
            }

            if (newNick.length() > 50) {
                newNick = stringFormatById("%s", getNickName(Long.parseLong(qq), entityTypeMessages));
            }

            if (newNick.length() > 50) {
                sender(entityTypeMessages, stringFormatById("[CQ:at,qq=%s]的卡名字太长了，无法改名", qq));
                continue;
            }
            if (checkPower(Long.parseLong(qq)).TYPE > checkPower(loginInfo.getLoginId()).TYPE) {
                sender(entityTypeMessages, stringFormatById("[CQ:at,qq=%s]的权限比本机更高，改名失败", qq));
                continue;
            }
            entityTypeMessages.getMsgSender().SETTER.setGroupCard(entityTypeMessages.getFromGroupString(), qq, newNick);
            sender(entityTypeMessages, stringFormatById("已尝试为[CQ:at,qq=%s]改名为:%s", qq, newNick));
        }
    }

    private void lock(long qqId) {
        String groupId = entityTypeMessages.getFromGroupString();
        String nick = makeNickToSender(getNickName(qqId, entityTypeMessages));
        String role = "";
        if (checkRoleChooseExistByQQ(qqId, groupId)) {
            role = getRoleChooseByQQ(qqId, groupId);
        }
        if (checkRoleLock(qqId, groupId)) {
            sender(entityTypeMessages, stringFormatById(entitySystemProperties.getTeamLock(entityTypeMessages.getFromGroupString()), nick, getRoleLockName(qqId, groupId, role)));
        } else {
            new InsertRoles().insertRoleLock(String.valueOf(qqId), groupId, role);
            sender(entityTypeMessages, stringFormatById(entitySystemProperties.getTeamLockChange(entityTypeMessages.getFromGroupString()), nick, role));
        }
    }

    private PowerType checkPower(long qqId) {
        return entityTypeMessages.getMsgSender().GETTER.getGroupMemberInfo(entityTypeMessages.getFromGroupString(), String.valueOf(qqId)).getPowerType();
    }
}
